﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;

namespace Clarius.Silverlight.Streaming.Library.Operations
{
    internal class UploadFileSetOperation : SilverlightStreamingOperation
    {
        String fileSetName;
        String applicationZipFile;
        const long BUFFER_SIZE = 4096;
        bool overwrite;

        internal UploadFileSetOperation(AccountManager accountManager, String fileSetName, String applicationZipFile, bool overwrite)
        {
            this.fileSetName = fileSetName;
            this.overwrite = overwrite;
            if (fileSetName.Length > 128)
            {
                throw new ArgumentOutOfRangeException("fileSetName", "fileSetName can not be longer than 128 characters");
            }
            this.applicationZipFile = applicationZipFile;
            if (!System.IO.File.Exists(applicationZipFile))
            {
                throw new FileNotFoundException("Can not find file '{0}'");
            }
            base.Initialize(accountManager);
        }

        protected override void HandleErrorFromHttpStatusCode(System.Net.HttpStatusCode statusCode, string errorText, Exception ex)
        {
            throw new SilverlightStreamingException(errorText, ex);
        }

        protected override WebRequest GetWebRequest()
        {
            // if we've been told to overwrite we need to check if a File Set with the same name already exists
            // so we delete it previous to trying the upload, otherwise the operation will fail as the
            // Silverlight Streaming Servers don't support overwritting of existing File Sets
            if (overwrite)
            {
                try
                {
                    // we will just attempt the delete operation as checking for the File Set existence first
                    // would be less performant
                    DeleteFileSetOperation dsfo = new DeleteFileSetOperation(accountManager, fileSetName);
                    dsfo.Execute();
                }
                catch (Exception e)
                {
                    // this could be because the File Set didn't really exist, which may happen
                    // or because something else went wrong, i.e. invalid server, invalid account, etc
                    // in which case the UploadFileSet operation would fail too.
                }
            }

            WebRequest request = WebUtil.GetWebRequest(accountManager.Account, "/" + fileSetName);
            request.Method = WebUtil.HTTP_METHOD_POST;
            request.ContentType = "application/zip";
            System.IO.FileInfo fileInfo = new FileInfo(applicationZipFile);
            request.ContentLength = fileInfo.Length;

            return request;
        }

        // we need to override the web request execution logic in this case as it is a bit more
        // complicated than the simpler logic for GET and DELETE requests.
        protected override HttpWebResponse ExecuteWebRequest(WebRequest request)
        {
            HttpWebResponse response = null;

            try
            {
                Stream requestStream = request.GetRequestStream();
                long bufferSize = request.ContentLength < BUFFER_SIZE ? request.ContentLength : BUFFER_SIZE;
                byte[] buffer = new Byte[bufferSize];
                int bytesRead = 0;
                // copy application .zip file to request stream
                using (FileStream fileStream = new FileStream(applicationZipFile,
                            FileMode.Open, FileAccess.Read))
                {
                    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        requestStream.Write(buffer, 0, bytesRead);
                    }
                }

                response = request.GetResponse() as HttpWebResponse;
            }
            catch (Exception ex)
            {
                HandleError(ex);
            }

            return response;
        }
    }
}
